﻿namespace Site2AppWP8.Modules
{
    using System;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Tasks;
    using Site2AppWP8.Config;

    public class RedirectModule
    {
        public const string RedirectActionName = "REDIRECT";
        public const string PopOutActionName = "POPOUT";
        public const string NotPopOutActionName = "NOTPOPOUT";
        public const string PopUpActionName = "POPUP";

        public static void InjectRedirectRulesSpys(WebConfig webConfig, WebBrowser browser)
        {
            if (webConfig.Redirects.IsEnabled && webConfig.Redirects.IsPopUpEnabled)
            {
                InjectLoadWindowOpenSpy(webConfig, browser);
            }
        }

        public static bool ApplyRedirectRules(WebBrowser webBrowser, NavigatingEventArgs e, WebConfig webConfig)
        {
            if (webConfig.Redirects.IsEnabled)
            {
                foreach (var rule in webConfig.Redirects.Rules)
                {
                    if (rule.Action.Equals(PopOutActionName, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(rule.Pattern))
                    {
                        if (System.Text.RegularExpressions.Regex.IsMatch(e.Uri.AbsoluteUri, rule.PatternRegex))
                        {
                            e.Cancel = true;

                            var task = new WebBrowserTask()
                            {
                                Uri = e.Uri
                            };

                            task.Show();

                            return true;
                        }
                    }
                    else if (rule.Action.Equals(RedirectActionName, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(rule.Pattern) && !string.IsNullOrWhiteSpace(rule.RedirectUrl))
                    {
                        if (System.Text.RegularExpressions.Regex.IsMatch(e.Uri.AbsoluteUri, rule.PatternRegex))
                        {
                            e.Cancel = true;

                            var redirectUri = new Uri(rule.RedirectUrl);
                            webBrowser.Navigate(redirectUri);

                            return true;
                        }
                    }
                }
            }

            return false;
        }

        public static bool CheckForMessages(string[] content, WebConfig webConfig, MainPage mainPage, WebDialogOverlay webDialogOverlay)
        {
            if (webConfig.Redirects.IsEnabled)
            {
                if (content[0].Equals("WINDOWOPEN", StringComparison.InvariantCultureIgnoreCase))
                {
                    var uri = GetAbsoluteUri(content, webConfig, mainPage);

                    foreach (var rule in webConfig.Redirects.Rules)
                    {
                        if (rule.Action.Equals(PopUpActionName, StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrWhiteSpace(rule.Pattern))
                        {
                            if (System.Text.RegularExpressions.Regex.IsMatch(uri.AbsoluteUri, rule.PatternRegex))
                            {
                                webDialogOverlay.StartWebDialog(uri, rule);
                                mainPage.ShowOverlay(webDialogOverlay);

                                return true;
                            }
                        }
                    }
                }

                if (content[0].Equals("WINDOWOPENEXTERNALBROWSER", StringComparison.InvariantCultureIgnoreCase))
                {
                    var uri = GetAbsoluteUri(content, webConfig, mainPage);

                    var task = new WebBrowserTask()
                    {
                        Uri = uri
                    };

                    task.Show();
                }
            }

            return false;
        }

        public static bool IsNotAnAppliedRedirectRule(WebConfig webConfig, Uri uri)
        {
            if (webConfig.Redirects.IsEnabled)
            {
                foreach (var rule in webConfig.Redirects.Rules)
                {
                    if (rule.Action.Equals(NotPopOutActionName, StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrWhiteSpace(rule.Pattern))
                    {
                        if (System.Text.RegularExpressions.Regex.IsMatch(uri.AbsoluteUri, rule.PatternRegex))
                        {
                            return false;
                        }
                    }
                }
            }

            return true;
        }

        private static Uri GetAbsoluteUri(string[] content, WebConfig webConfig, MainPage mainPage)
        {
            var url = content[1];

            var uri = new Uri(url, UriKind.RelativeOrAbsolute);

            if (!uri.IsAbsoluteUri)
            {
                if (url.StartsWith("/"))
                {
                    // path from root
                    uri = new Uri(webConfig.BaseURL, url);
                }
                else
                {
                    // relative path
                    uri = new Uri(mainPage.Browser.Source, url);
                }
            }

            return uri;
        }

        private static void InjectLoadWindowOpenSpy(WebConfig webConfig, WebBrowser browser)
        {
            var scriptString = "(function() {\n" +
                            "var captureWindowOpenMatch, " +
                                "notPopOutMatch, " +
                                "openWindow = window.open;\n" +
                            "window.open = function() {\n" +
                                "console.log('intercepted window.open going to: ' + arguments[0]);\n" +
                                "captureWindowOpenMatch = false;\n" +
                                "notPopOutMatch = false;\n";

            // see if the request URL matches a redirect rule...
            foreach (var rule in webConfig.Redirects.Rules)
            {
                if (rule.Action.Equals(PopUpActionName, StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrWhiteSpace(rule.Pattern))
                {
                    scriptString += "if (/" + rule.PatternRegex.Replace("/", "\\/") + "/.test(arguments[0])) { captureWindowOpenMatch = true; }\n";
                }

                if (rule.Action.Equals(NotPopOutActionName, StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrWhiteSpace(rule.Pattern))
                {
                    scriptString += "if (/" + rule.PatternRegex.Replace("/", "\\/") + "/.test(arguments[0])) { notPopOutMatch = true; }\n";
                }
            }

            scriptString +=
                    "if (captureWindowOpenMatch) {\n" +
                        "console.log('There is a captureWindowOpen match with ' + arguments[0]);\n" +
                        "window.external.notify('WINDOWOPEN~~' + arguments[0]);\n" +
                        "return {};\n" +
                    "} else if (notPopOutMatch) {\n" +
                        "console.log('There is a notPopOut match with ' + arguments[0]);\n" +
                        "window.location.assign(location.protocol + '//' +window.location.hostname + arguments[0]);" +
                        "return {};\n" +
                    "} else {\n" +  // if none of the redirect rules matched open as normal (external browser)
                        "console.log('There is no match for ' + arguments[0]);\n" +
                        "window.external.notify('WINDOWOPENEXTERNALBROWSER~~' + arguments[0]);\n" +
                        "return {};\n" +
                    "}\n" +
                "};\n" + // end of window.open override
            "})();";

            browser.TryToRunScript(scriptString);
        }
    }
}
